home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / daten / astrolog / src / xcharts1.c < prev    next >
C/C++ Source or Header  |  1995-08-11  |  44KB  |  1,411 lines

  1. /*                                                               -*- C -*-
  2. ** Astrolog (Version 4.40) File: xcharts1.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. /* $VER: $Id: xcharts1.c,v 1.4 1995/07/02 22:22:29 tf Exp $ */
  38.  
  39. #include "astrolog.h"
  40.  
  41.  
  42. #ifdef GRAPH
  43. /*
  44. ******************************************************************************
  45. ** Single Chart Graphics Routines.
  46. ******************************************************************************
  47. */
  48.  
  49. /* Draw a wheel chart, in which the 12 signs and houses are delineated, and  */
  50. /* the planets are inserted in their proper places. This is the default      */
  51. /* graphics chart to generate, as is done when the -v or -w (or no) switches */
  52. /* are included with -X. Draw the aspects in the middle of chart, too.       */
  53.  
  54. void XChartWheel()
  55. {
  56.   real xsign[cSign+1], xhouse[cSign+1], xplanet[objMax], symbol[objMax];
  57.   int cx, cy, i, j;
  58.   real asc, unitx, unity, px, py, temp;
  59.  
  60.   /* Set up variables and temporarily automatically decrease the horizontal */
  61.   /* chart size to leave room for the sidebar if that mode is in effect.    */
  62.  
  63.   if (gs.fText && !us.fVelocity)
  64.     gs.xWin -= xSideT;
  65.  
  66.   cx = gs.xWin/2 - 1; cy = gs.yWin/2 - 1;
  67.   unitx = (real)cx; unity = (real)cy;
  68.   asc = gs.nLeft ? planet[abs(gs.nLeft)]+90*(gs.nLeft < 0) : house[1];
  69.  
  70.   /* Fill out arrays with the angular degree on the circle of where to    */
  71.   /* place each object, cusp, and sign glyph based on how the chart mode. */
  72.  
  73.   if (gi.nMode == gWheel) 
  74.   {
  75.     for (i = 1; i <= cSign; i++)
  76.       xhouse[i] = PZ(house[i]);
  77.   } 
  78.  
  79.   else /* !gWheel */
  80.   {
  81.     asc -= house[1];
  82.     for (i = 1; i <= cSign; i++)
  83.       xhouse[i] = PZ(ZFromS(i));
  84.   }
  85.  
  86.   for (i = 1; i <= cSign; i++)
  87.     xsign[i] = PZ(HousePlaceInX(ZFromS(i)));
  88.  
  89.   for (i = 1; i <= cObj; i++)
  90.     xplanet[i] = PZ(HousePlaceInX(planet[i]));
  91.  
  92.   /* Draw Ascendant/Descendant and Midheaven/Nadir lines across whole chart. */
  93.  
  94.   DrawColor(gi.kiLite);
  95.  
  96.   DrawDash(cx+POINT1(unitx, 0.99, PX(xhouse[sAri])),
  97.            cy+POINT1(unity, 0.99, PY(xhouse[sAri])),
  98.            cx+POINT1(unitx, 0.99, PX(xhouse[sLib])),
  99.            cy+POINT1(unity, 0.99, PY(xhouse[sLib])), !gs.fColor);
  100.  
  101.   DrawDash(cx+POINT1(unitx, 0.99, PX(xhouse[sCap])),
  102.            cy+POINT1(unity, 0.99, PY(xhouse[sCap])),
  103.            cx+POINT1(unitx, 0.99, PX(xhouse[sCan])),
  104.            cy+POINT1(unity, 0.99, PY(xhouse[sCan])), !gs.fColor);
  105.  
  106.   /* Draw small five or one degree increments around the zodiac sign ring. */
  107.  
  108.   for (i = 0; i < nDegMax; i ++) 
  109.   {
  110.     temp = PZ(HousePlaceInX((real)i));
  111.     px = PX(temp); py = PY(temp);
  112.  
  113.     DrawColor(i%5 ? gi.kiGray : gi.kiOn);
  114.     DrawDash(cx+POINT1(unitx, 0.75, px), cy+POINT1(unity, 0.75, py),
  115.              cx+POINT2(unitx, 0.80, px), cy+POINT2(unity, 0.80, py),
  116.       ((!gs.fColor || gs.fPS || gs.fMeta) && i%5)*2);
  117.   }
  118.  
  119.   /* Draw circles for the zodiac sign and house rings. */
  120.  
  121.   DrawColor(gi.kiOn);
  122.   DrawCircle(cx, cy, (int)(unitx*0.95+rRound), (int)(unity*0.95+rRound));
  123.   DrawCircle(cx, cy, (int)(unitx*0.80+rRound), (int)(unity*0.80+rRound));
  124.   DrawCircle(cx, cy, (int)(unitx*0.75+rRound), (int)(unity*0.75+rRound));
  125.   DrawCircle(cx, cy, (int)(unitx*0.65+rRound), (int)(unity*0.65+rRound));
  126.  
  127.   /* Draw the glyphs for the signs and houses themselves. */
  128.  
  129.   for (i = 1; i <= cSign; i++) 
  130.   {
  131.     temp = xsign[i];
  132.  
  133.     DrawColor(gi.kiOn);
  134.     DrawLine(cx+POINT2(unitx, 0.95, PX(temp)),    /* Draw lines separating */
  135.              cy+POINT2(unity, 0.95, PY(temp)),    /* each sign and house   */
  136.              cx+POINT1(unitx, 0.80, PX(temp)),    /* from each other.      */
  137.              cy+POINT1(unity, 0.80, PY(temp)));
  138.  
  139.     DrawLine(cx+POINT2(unitx, 0.75, PX(xhouse[i])),
  140.              cy+POINT2(unity, 0.75, PY(xhouse[i])),
  141.              cx+POINT1(unitx, 0.65, PX(xhouse[i])),
  142.              cy+POINT1(unity, 0.65, PY(xhouse[i])));
  143.  
  144.     if (gs.fColor && i%3 != 1)
  145.     {                                                              /* Lines from */
  146.       DrawColor(gi.kiGray);                                        /* each house */
  147.       DrawDash(cx, cy, cx+POINT2(unitx, 0.65, PX(xhouse[i])),      /* to center  */
  148.                        cy+POINT2(unity, 0.65, PY(xhouse[i])), 1);  /* of wheel.  */
  149.     }
  150.  
  151.     temp = Midpoint(temp, xsign[Mod12(i+1)]);
  152.  
  153.     DrawColor(kSignB(i));
  154.     DrawSign(i, cx+POINT1(unitx, 0.875, PX(temp)),
  155.                 cy+POINT1(unity, 0.875, PY(temp)));
  156.  
  157.     temp = Midpoint(xhouse[i], xhouse[Mod12(i+1)]);
  158.  
  159.     DrawHouse(i, cx+POINT1(unitx, 0.70, PX(temp)),
  160.                  cy+POINT1(unity, 0.70, PY(temp)));
  161.   }
  162.  
  163.   for (i = 1; i <= cObj; i++)    /* Figure out where to put planet glyphs. */
  164.     symbol[i] = xplanet[i];
  165.  
  166.   FillSymbolRing(symbol);
  167.  
  168.   /* For each planet, draw a small dot indicating where it is, and then */
  169.   /* a line from that point to the planet's glyph.                      */
  170.  
  171.   for (i = cObj; i >= 1; i--) if (FProper(i))
  172.   {
  173.     if (gs.fLabel)
  174.     {
  175.       temp = symbol[i];
  176.  
  177.       DrawColor(ret[i] < 0.0 ? gi.kiGray : gi.kiOn);
  178.  
  179.       DrawDash(cx+POINT1(unitx, 0.52, PX(xplanet[i])),
  180.                cy+POINT1(unity, 0.52, PY(xplanet[i])),
  181.                cx+POINT1(unitx, 0.56, PX(temp)),
  182.                cy+POINT1(unity, 0.56, PY(temp)),       (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  183.  
  184.       DrawObject(i, cx+POINT1(unitx, 0.60, PX(temp)),
  185.                     cy+POINT1(unity, 0.60, PY(temp)));
  186.     }
  187.     else DrawColor(kObjB[i]);
  188.  
  189.     DrawPoint(cx+POINT1(unitx, 0.50, PX(xplanet[i])),
  190.               cy+POINT1(unity, 0.50, PY(xplanet[i])));
  191.   }
  192.  
  193.   /* Draw lines connecting planets which have aspects between them. */
  194.  
  195.   if (!gs.fAlt)                  /* Don't draw aspects in bonus mode. */
  196.   {
  197.     if (!FCreateGrid(fFalse))
  198.       return;
  199.  
  200.     for (j = cObj; j >= 2; j--)
  201.     {
  202.       for (i = j-1; i >= 1; i--)
  203.       {
  204.         if (grid->n[i][j] && FProper(i) && FProper(j))  
  205.         {
  206.           DrawColor(kAspB[grid->n[i][j]]);
  207.           DrawDash(cx+POINT1(unitx, 0.48, PX(xplanet[i])),
  208.                    cy+POINT1(unity, 0.48, PY(xplanet[i])),
  209.                    cx+POINT1(unitx, 0.48, PX(xplanet[j])),
  210.                    cy+POINT1(unity, 0.48, PY(xplanet[j])),  abs(grid->v[i][j]/60/2));
  211.         }
  212.       }
  213.     }
  214.   }
  215.  
  216.   /* Go draw sidebar with chart information and positions if need be. */
  217.  
  218.   DrawInfo();
  219. }
  220.  
  221.  
  222. /* Draw an astro-graph chart on a map of the world, i.e. the draw the     */
  223. /* Ascendant, Descendant, Midheaven, and Nadir lines corresponding to the */
  224. /* time in the chart. This chart is done when the -L switch is combined   */
  225. /* with the -X switch.                                                    */
  226.  
  227. void XChartAstroGraph()
  228. {
  229.   real planet1[objMax], planet2[objMax],
  230.     end1[cObj*2+1], end2[cObj*2+1],
  231.     symbol1[cObj*2+1], symbol2[cObj*2+1],
  232.     lon = Lon, longm, x, y, z, ad, oa, am, od, dm, lat;
  233.  
  234.   int unit = gi.nScale, fStroke, lat1 = -60, lat2 = 75, y1, y2, xold1, xold2,
  235.     i, j, k, l;
  236.  
  237.   /* Erase top and bottom parts of map. We don't draw the astro-graph lines */
  238.   /* above certain latitudes, and this gives us room for glyph labels, too. */
  239.  
  240.   y1 = (91-lat1)*gi.nScale;
  241.   y2 = (91-lat2)*gi.nScale;
  242.  
  243.   DrawColor(gi.kiOff);
  244.   DrawBlock(0, 1, gs.xWin-1, y2-1);
  245.   DrawBlock(0, gs.yWin-2, gs.xWin-1, y1+1);
  246.   DrawColor(gi.kiLite);
  247.   DrawDash(0, gs.yWin/2, gs.xWin-2, gs.yWin/2, 4);    /* Draw equator. */
  248.  
  249.   DrawColor(gi.kiOn);
  250.   DrawLine(1, y2, gs.xWin-2, y2);
  251.   DrawLine(1, y1, gs.xWin-2, y1);
  252.  
  253.   for (i = 1; i <= cObj*2; i++)
  254.     end1[i] = end2[i] = -rLarge;
  255.  
  256.   /* Draw small hatches every 5 degrees along edges of world map. */
  257.  
  258.   DrawColor(gi.kiLite);
  259.  
  260.   for (i = lat1; i <= lat2; i += 5)
  261.   {
  262.     j = (91-i)*gi.nScale;
  263.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  264.     DrawLine(1, j, k, j);
  265.     DrawLine(gs.xWin-2, j, gs.xWin-1-k, j);
  266.   }
  267.  
  268.   for (i = -180; i < 180; i += 5)
  269.   {
  270.     j = (180-i)*gi.nScale;
  271.     k = (2+(i%10 == 0)+2*(i%30 == 0)+(i%90 == 0))*gi.nScaleT;
  272.     DrawLine(j, y2+1, j, y2+k);
  273.     DrawLine(j, y1-1, j, y1-k);
  274.   }
  275.  
  276.   if (us.fLatitudeCross) 
  277.   {
  278.     DrawColor(kRainbowB[7]);
  279.     i = (int)((91.0-Lat)*(real)gi.nScale);
  280.     DrawLine(0, i, gs.xWin-1, i);
  281.   }
  282.  
  283. #ifdef MATRIX
  284.  
  285.   /* Calculate zenith locations of each planet. */
  286.  
  287.   for (i = 1; i <= cObj; i++) if (!ignore[i])
  288.   {
  289.     planet1[i] = RFromD(Tropical(planet[i]));
  290.     planet2[i] = RFromD(planetalt[i]);
  291.     EclToEqu(&planet1[i], &planet2[i]);
  292.   }
  293.  
  294.   /* Draw the Midheaven lines and zenith location markings. */
  295.  
  296.   if (lon < 0.0)
  297.     lon += rDegMax;
  298.  
  299.   for (i = 1; i <= cObj; i++) if (FProper(i))
  300.   {
  301.     x = RFromD(MC)-planet1[i];
  302.  
  303.     if (x < 0.0)  x += 2.0*rPi;
  304.     if (x > rPi)  x -= 2.0*rPi;
  305.  
  306.     z = lon+DFromR(x);
  307.  
  308.     if (z > rDegHalf)
  309.       z -= rDegMax;
  310.  
  311.     j = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  312.  
  313.     DrawColor(kElemB[eEar]);
  314.     DrawLine(j, y1+unit*4, j, y2-unit*1);
  315.  
  316.     end2[i*2-1] = (real)j;
  317.  
  318.     y = DFromR(planet2[i]);
  319.     k = (int)((91.0-y)*(real)gi.nScale);
  320.  
  321.     if (FBetween((int)y, lat1, lat2))
  322.     {
  323.       DrawColor(gi.kiLite);
  324.       DrawBlock(j-1, k-1, j+1, k+1);
  325.       DrawColor(gi.kiOff);
  326.       DrawBlock(j, k, j, k);
  327.     }
  328.  
  329.     /* Draw Nadir lines assuming we aren't in bonus chart mode. */
  330.  
  331.     if (!gs.fAlt) 
  332.     {
  333.       j += 180*gi.nScale;
  334.  
  335.       if (j > gs.xWin-2)
  336.         j -= (gs.xWin-2);
  337.  
  338.       end1[i*2-1] = (real)j;
  339.  
  340.       DrawColor(kElemB[eWat]);
  341.       DrawLine(j, y1+unit*2, j, y2-unit*2);
  342.     }
  343.   }
  344.  
  345.   /* Now, normally, unless we are in bonus chart mode, we will go on to draw */
  346.   /* the Ascendant and Descendant lines here.                                */
  347.  
  348.   longm = RFromD(Mod(MC+lon));
  349.   if (!gs.fAlt) for (i = 1; i <= cObj; i++) if (FProper(i)) 
  350.   {
  351.     xold1 = xold2 = -1000;
  352.  
  353.     /* Hack: Normally we draw the Ascendant and Descendant line segments  */
  354.     /* simultaneously. However, for the PostScript and metafile stroke    */
  355.     /* graphics, this will case the file to get inordinately large due to */
  356.     /* the constant thrashing between the Asc and Desc colors. Hence for  */
  357.     /* these charts only, we'll do two passes for Asc and Desc.           */
  358.  
  359.     fStroke = gs.fPS || gs.fMeta;
  360.  
  361.     for (l = 0; l <= fStroke; l++)
  362.     {
  363.       for (lat = (real)lat1; lat <= (real)lat2; lat += 1.0/(real)(gi.nScale/gi.nScaleT))
  364.       {
  365.         /* First compute and draw the current segment of Ascendant line. */
  366.  
  367.         j = (int)((91.0-lat)*(real)gi.nScale);
  368.         ad = RTan(planet2[i])*RTan(RFromD(lat));
  369.  
  370.         if (ad*ad > 1.0)
  371.           ad = rLarge;
  372.  
  373.         else 
  374.         {
  375.           ad = RAsin(ad);
  376.           oa = planet1[i]-ad;
  377.           if (oa < 0.0)
  378.             oa += 2.0*rPi;
  379.           am = oa-rPiHalf;
  380.           if (am < 0.0)
  381.             am += 2.0*rPi;
  382.           z = longm-am;
  383.           if (z < 0.0)  z += 2.0*rPi;
  384.           if (z > rPi)  z -= 2.0*rPi;
  385.           z = DFromR(z);
  386.           k = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  387.  
  388.           if (!fStroke || !l)
  389.           {
  390.             DrawColor(kElemB[eFir]);
  391.             DrawWrap(xold1, j+gi.nScaleT, k, j, 1, gs.xWin-2);
  392.  
  393.             if (lat == (real)lat1)                            /* Line segment */
  394.             {
  395.               DrawLine(k, y1, k, y1+unit*4);                  /* pointing to  */
  396.               end2[i*2] = (real)k;                            /* Ascendant.   */
  397.             }
  398.           } 
  399.           else if (lat == (real)lat1)
  400.             end2[i*2] = (real)k;
  401.  
  402.           xold1 = k;
  403.         }
  404.  
  405.         /* The curving Ascendant and Descendant lines actually touch each at  */
  406.         /* low latitudes. Sometimes when we start out, a particular planet's  */
  407.         /* lines haven't appeared yet, i.e. we are scanning at a latitude     */
  408.         /* where our planet's lines don't exist. If this is the case, then    */
  409.         /* when they finally do start, draw a thin horizontal line connecting */
  410.         /* the Ascendant and Descendant lines so they don't just start in     */
  411.         /* space. Note that these connected lines aren't labeled with glyphs. */
  412.  
  413.         if (ad == rLarge) 
  414.         {
  415.           if (xold1 >= 0)
  416.           {
  417.             if (!fStroke || !l) 
  418.             {
  419.               DrawColor(gi.kiGray);
  420.               DrawWrap(xold1, j+1, xold2, j+1, 1, gs.xWin-2);
  421.             }
  422.             lat = rDegQuad;
  423.           }
  424.         }
  425.  
  426.         else
  427.         {
  428.           /* Then compute and draw corresponding segment of Descendant line. */
  429.  
  430.           od = planet1[i]+ad;
  431.           dm = od+rPiHalf;
  432.           z = longm-dm;
  433.           if (z < 0.0)  z += 2.0*rPi;
  434.           if (z > rPi)  z -= 2.0*rPi;
  435.           z = DFromR(z);
  436.  
  437.           k = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  438.  
  439.           if (xold2 < 0 && lat > (real)lat1 && (!fStroke || l)) 
  440.           {
  441.             DrawColor(gi.kiGray);
  442.             DrawWrap(xold1, j, k, j, 1, gs.xWin-2);
  443.           }
  444.  
  445.           if (!fStroke || l)
  446.           {
  447.             DrawColor(kElemB[eAir]);
  448.             DrawWrap(xold2, j+gi.nScaleT, k, j, 1, gs.xWin-2);
  449.  
  450.             if (lat == (real)lat1)                            /* Line segment */
  451.               DrawLine(k, y1, k, y1+unit*2);                  /* pointing to  */
  452.           }                                                   /* Descendant.  */
  453.           xold2 = k;
  454.         }
  455.       }
  456.     }
  457.  
  458. #endif /* MATRIX */
  459.  
  460.     /* Draw segments pointing to top of Ascendant and Descendant lines. */
  461.  
  462.     if (ad != rLarge) 
  463.     {
  464.       DrawColor(kElemB[eFir]);
  465.       DrawLine(xold1, y2, xold1, y2-unit*1);
  466.  
  467.       DrawColor(kElemB[eAir]);
  468.       DrawLine(k, y2, k, y2-unit*2);
  469.       end1[i*2] = (real)k;
  470.     }
  471.   }
  472.  
  473.   DrawColor(kMainB[8]);
  474.   i = (int)((181.0-Lon)*(real)gi.nScale);
  475.   j = (int)((91.0-Lat)*(real)gi.nScale);
  476.  
  477.   if (us.fLatitudeCross)
  478.     DrawSpot(i, j);
  479.   else
  480.     DrawPoint(i, j);
  481.  
  482.   /* Determine where to draw the planet glyphs. We have four sets of each    */
  483.   /* planet - each planet's glyph appearing in the chart up to four times -  */
  484.   /* one for each type of line. The Midheaven and Ascendant lines are always */
  485.   /* labeled at the bottom of the chart, while the Nadir and Midheaven lines */
  486.   /* at the top. Therefore we need to place two sets of glyphs, twice.       */
  487.  
  488.   for (i = 1; i <= cObj*2; i++)
  489.   {
  490.     symbol1[i] = end1[i];
  491.     symbol2[i] = end2[i];
  492.   }
  493.  
  494.   FillSymbolLine(symbol1);
  495.   FillSymbolLine(symbol2);
  496.  
  497.   /* Now actually draw the planet glyphs. */
  498.  
  499.   for (i = 1; i <= cObj*2; i++)
  500.   {
  501.     j = (i+1)/2;
  502.  
  503.     if (FProper(j))
  504.     {
  505.       if ((gi.xTurtle = (int)symbol1[i]) > 0 && gs.fLabel) 
  506.       {
  507.         DrawColor(ret[j] < 0.0 ? gi.kiGray : gi.kiOn);
  508.         DrawDash((int)end1[i], y2-unit*2, (int)symbol1[i], y2-unit*4, (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  509.         DrawObject(j, gi.xTurtle, y2-unit*10);
  510.       }
  511.  
  512.       if ((gi.xTurtle = (int)symbol2[i]) > 0)
  513.       {
  514.         DrawColor(ret[j] < 0.0 ? gi.kiGray : gi.kiOn);
  515.         DrawDash((int)end2[i], y1+unit*4, (int)symbol2[i], y1+unit*8, (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  516.         DrawObject(j, gi.xTurtle, y1+unit*14);
  517.         DrawTurtle(szDrawObject[i & 1 ? oMC : oAsc], (int)symbol2[i], y1+unit*24-gi.nScaleT);
  518.       }
  519.     }
  520.   }
  521. }
  522.  
  523.  
  524. /* Draw an aspect and midpoint grid in the window, with planets labeled down */
  525. /* the diagonal. This chart is done when the -g switch is combined with the  */
  526. /* -X switch. The chart always has a certain number of cells; hence based    */
  527. /* how the restrictions are set up, there may be blank columns and rows,     */
  528. /* or else only the first number of unrestricted objects will be included.   */
  529.  
  530. void XChartGrid()
  531. {
  532.   char sz[cchSzDef];
  533.   int unit, siz, x, y, i, j, k;
  534.   KI c;
  535.  
  536.   unit = CELLSIZE*gi.nScale; siz = gs.nGridCell*unit;
  537.   if (!FCreateGrid(gs.fAlt))
  538.     return;
  539.  
  540.   /* Loop through each cell in each row and column of grid. */
  541.  
  542.   for (y = 1, j = 0; y <= gs.nGridCell; y++) {
  543.     do {
  544.       j++;
  545.     } while (ignore[j] && j <= cObj);
  546.     DrawColor(gi.kiGray);
  547.     DrawDash(0, y*unit, siz, y*unit, !gs.fColor);
  548.     DrawDash(y*unit, 0, y*unit, siz, !gs.fColor);
  549.  
  550.     if (j <= cObj) for (x = 1, i = 0; x <= gs.nGridCell; x++) 
  551.     {
  552.       do { i++; } while (ignore[i] && i <= cObj);
  553.  
  554.       if (i <= cObj)
  555.       {
  556.         gi.xTurtle = x*unit-unit/2;
  557.         gi.yTurtle = y*unit-unit/2 - (gi.nScale/gi.nScaleT > 2 ? 5*gi.nScaleT : 0);
  558.         k = grid->n[i][j];
  559.  
  560.         /* If this is an aspect cell, draw glyph of aspect in effect. */
  561.  
  562.         if (gs.fAlt ? x > y : x < y) 
  563.         {
  564.           if (k) 
  565.           {
  566.             DrawColor(c = kAspB[k]);
  567.             DrawAspect(k, gi.xTurtle, gi.yTurtle);
  568.           }
  569.         }
  570.  
  571.         /* If this is a midpoint cell, draw glyph of sign of midpoint. */
  572.  
  573.         else if (gs.fAlt ? x < y : x > y)
  574.         {
  575.           DrawColor(c = kSignB(grid->n[i][j]));
  576.           DrawSign(grid->n[i][j], gi.xTurtle, gi.yTurtle);
  577.         }
  578.  
  579.         /* For cells on main diagonal, draw glyph of planet. */
  580.  
  581.         else 
  582.         {
  583.           DrawColor(gi.kiLite);
  584.           DrawEdge((y-1)*unit, (y-1)*unit, y*unit, y*unit);
  585.           DrawObject(i, gi.xTurtle, gi.yTurtle);
  586.         }
  587.  
  588.         /* When the scale size is 300+, we can print text in each cell: */
  589.  
  590.         if (gi.nScale/gi.nScaleT > 2 && gs.fLabel) 
  591.         {
  592.           k = abs(grid->v[i][j]);
  593.  
  594.           /* For the aspect portion, print the orb in degrees and minutes. */
  595.  
  596.           if (gs.fAlt ? x > y : x < y)
  597.           {
  598.             if (grid->n[i][j])
  599.               sprintf(sz, "%c%d %02d'", k != grid->v[i][j] ? (us.fAppSep ? 'a' : '-')
  600.                                                            : (us.fAppSep ? 's' : '+'), k/60, k%60);
  601.             else
  602.               sprintf(sz, "");
  603.  
  604.           /* For the midpoint portion, print the degrees and minutes. */
  605.  
  606.           } 
  607.           else if (gs.fAlt ? x < y : x > y)
  608.             sprintf(sz, "%2d %02d'", k/60, k%60);
  609.  
  610.           /* For the main diagonal, print degree and sign of each planet. */
  611.  
  612.           else 
  613.           {
  614.             c = kSignB(grid->n[i][j]);
  615.             sprintf(sz, "%c%c%c %02d", chSig3(grid->n[i][j]), k);
  616.           }
  617.  
  618.           DrawColor(c);
  619.           DrawSz(sz, x*unit-unit/2, y*unit-3*gi.nScaleT, dtBottom);
  620.         }
  621.       }
  622.     }
  623.   }
  624. }
  625.  
  626.  
  627. /* Draw the local horizon, and draw in the planets where they are at the */
  628. /* time in question, as done when the -Z is combined with the -X switch. */
  629.  
  630. void XChartHorizon()
  631. {
  632.   real lat, lonz[objMax], latz[objMax], azi[objMax], alt[objMax];
  633.   int x[objMax], y[objMax], m[objMax], n[objMax],
  634.     cx, cy, unit, x1, y1, x2, y2, xs, ys, i, j, k, l;
  635.   char sz[2];
  636.  
  637.   unit = Max(12, 6*gi.nScale);
  638.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  639.   unit = 12*gi.nScale;
  640.   xs = x2-x1; ys = y2-y1; cx = (x1+x2)/2; cy = (y1+y2)/2;
  641.  
  642.   /* Make a slightly smaller rectangle within the window to draw the planets */
  643.   /* in. Make segments on all four edges marking 5 degree increments.        */
  644.  
  645.   DrawColor(gi.kiLite);
  646.  
  647.   for (i = 5; i < 180; i += 5)
  648.   {
  649.     j = y1+(int)((real)i*(real)ys/rDegHalf);
  650.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  651.     DrawLine(x1+1, j, x1+1+k, j);
  652.     DrawLine(x2-1, j, x2-1-k, j);
  653.   }
  654.   sz[1] = chNull;
  655.  
  656.   for (i = 5; i < nDegMax; i += 5)
  657.   {
  658.     j = x1+(int)((real)i*(real)xs/rDegMax);
  659.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  660.     DrawLine(j, y1+1, j, y1+1+k);
  661.     DrawLine(j, y2-1, j, y2-1-k);
  662.     if (i % 90 == 0) {
  663.       *sz = *szDir[i/90 & 3];
  664.       DrawSz(sz, j, y1-2*gi.nScaleT, dtBottom);
  665.     }
  666.   }
  667.  
  668.   /* Draw vertical lines dividing our rectangle into four areas. In our     */
  669.   /* local space chart, the middle line represents due south, the left line */
  670.   /* due east, the right line due west, and the edges due north. A fourth   */
  671.   /* horizontal line divides that which is above and below the horizon.     */
  672.  
  673.   DrawColor(gi.kiGray);
  674.   DrawDash(cx, y1, cx, y2, 1);
  675.   DrawDash((cx+x1)/2, y1, (cx+x1)/2, y2, 1);
  676.   DrawDash((cx+x2)/2, y1, (cx+x2)/2, y2, 1);
  677.   DrawColor(gi.kiOn);
  678.   DrawEdge(x1, y1, x2, y2);
  679.   DrawDash(x1, cy, x2, cy, 1);
  680.  
  681.   /* Calculate the local horizon coordinates of each planet. First convert */
  682.   /* zodiac position and declination to zenith longitude and latitude.     */
  683.  
  684.   lat = RFromD(Lat);
  685.   for (i = 1; i <= cObj; i++) if (!ignore[i] || i == oMC)
  686.   {
  687.     lonz[i] = RFromD(Tropical(planet[i])); latz[i] = RFromD(planetalt[i]);
  688.     EclToEqu(&lonz[i], &latz[i]);
  689.   }
  690.   for (i = 1; i <= cObj; i++) if (FProper(i)) 
  691.   {
  692.     lonz[i] = RFromD(Mod(DFromR(lonz[oMC]-lonz[i]+rPiHalf)));
  693.     EquToLocal(&lonz[i], &latz[i], rPiHalf-lat);
  694.     azi[i] = rDegMax-DFromR(lonz[i]); alt[i] = DFromR(latz[i]);
  695.     x[i] = x1+(int)((real)xs*(Mod(rDegQuad-azi[i]))/rDegMax+rRound);
  696.     y[i] = y1+(int)((real)ys*(rDegQuad-alt[i])/rDegHalf+rRound);
  697.     m[i] = x[i]; n[i] = y[i]+unit/2;
  698.   }
  699.  
  700.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  701.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  702.   /* drawn on top of each other if possible. Again, we assume that we'll */
  703.   /* put the glyph right under the point, unless there would be some     */
  704.   /* overlap and the above position is better off.                       */
  705.  
  706.   for (i = 1; i <= cObj; i++) if (FProper(i)) 
  707.   {
  708.     k = l = gs.xWin+gs.yWin;
  709.     for (j = 1; j < i; j++) if (FProper(j)) {
  710.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  711.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  712.     }
  713.     if (k < unit || l < unit)
  714.       if (k < l)
  715.         n[i] -= unit;
  716.   }
  717.  
  718.   for (i = cObj; i >= 1; i--) if (FProper(i))    /* Draw planet's glyph. */
  719.     DrawObject(i, m[i], n[i]);
  720.  
  721.   for (i = cObj; i >= 1; i--) if (FProper(i)) 
  722.   {
  723.     DrawColor(kObjB[i]);
  724.     if (!gs.fAlt || i > oNorm)
  725.       DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  726.     else                          /* near glyph indicating   */
  727.       DrawSpot(x[i], y[i]);       /* exact local location.   */
  728.   }
  729. }
  730.  
  731.  
  732. /* Draw the local horizon, and draw in the planets where they are at the  */
  733. /* time in question. This chart is done when the -Z0 is combined with the */
  734. /* -X switch. This is an identical function to XChartHorizon(); however,  */
  735. /* that routine's chart is entered on the horizon and meridian. Here we   */
  736. /* center the chart around the center of the sky straight up from the     */
  737. /* local horizon, with the horizon itself being an encompassing circle.   */
  738.  
  739. void XChartHorizonSky()
  740. {
  741.   real lat, rx, ry, s, sqr2,
  742.     lonz[objMax], latz[objMax], azi[objMax], alt[objMax];
  743.   int x[objMax], y[objMax], m[objMax], n[objMax],
  744.     cx, cy, unit, x1, y1, x2, y2, xs, ys, i, j, k, l;
  745.  
  746.   unit = Max(12, 6*gi.nScale);
  747.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  748.   unit = 12*gi.nScale;
  749.   xs = x2-x1; ys = y2-y1; cx = (x1+x2)/2; cy = (y1+y2)/2;
  750.  
  751.   /* Draw a circle in window to indicate horizon line, lines dividing   */
  752.   /* the window into quadrants to indicate n/s and w/e meridians, and   */
  753.   /* segments on these lines and the edges marking 5 degree increments. */
  754.  
  755.   sqr2 = RSqr(2.0);
  756.   DrawColor(gi.kiGray);
  757.   DrawDash(cx, y1, cx, y2, 1);
  758.   DrawDash(x1, cy, x2, cy, 1);
  759.   DrawColor(gi.kiLite);
  760.  
  761.   for (i = -125; i <= 125; i += 5) 
  762.   {
  763.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  764.     s = 1.0/(rDegQuad*sqr2);
  765.     j = cy+(int)(s*ys/2*i);
  766.     DrawLine(cx-k, j, cx+k, j);
  767.     j = cx+(int)(s*xs/2*i);
  768.     DrawLine(j, cy-k, j, cy+k);
  769.   }
  770.  
  771.   for (i = 5; i < 55; i += 5) {
  772.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  773.     s = 1.0/(rDegHalf-rDegQuad*sqr2);
  774.     j = (int)(s*ys/2*i);
  775.     DrawLine(x1, y1+j, x1+k, y1+j);
  776.     DrawLine(x1, y2-j, x1+k, y2-j);
  777.     DrawLine(x2, y1+j, x2-k, y1+j);
  778.     DrawLine(x2, y2-j, x2-k, y2-j);
  779.     j = (int)(s*xs/2*i);
  780.     DrawLine(x1+j, y1, x1+j, y1+k);
  781.     DrawLine(x2-j, y1, x2-j, y1+k);
  782.     DrawLine(x1+j, y2, x1+j, y2-k);
  783.     DrawLine(x2-j, y2, x2-j, y2-k);
  784.   }
  785.  
  786.   DrawSz("N", cx, y1-2*gi.nScaleT, dtBottom);
  787.   DrawSz("E", x1/2, cy+2*gi.nScaleT, dtCent);
  788.   DrawSz("W", (gs.xWin+x2)/2, cy+2*gi.nScaleT, dtCent);
  789.  
  790.   if (!gs.fText)
  791.     DrawSz("S", cx, gs.yWin-3*gi.nScaleT, dtBottom);
  792.  
  793.   rx = xs/2/sqr2; ry = ys/2/sqr2;
  794.  
  795.   DrawColor(gi.kiOn);
  796.   DrawEdge(x1, y1, x2, y2);
  797.   DrawCircle(cx, cy, (int)rx, (int)ry);
  798.  
  799.   for (i = 0; i < nDegMax; i += 5) 
  800.   {
  801.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  802.     DrawLine(cx+(int)((rx-k)*RCosD((real)i)), cy+(int)((ry-k)*RSinD((real)i)),
  803.       cx+(int)((rx+k)*RCosD((real)i)), cy+(int)((ry+k)*RSinD((real)i)));
  804.   }
  805.  
  806.   /* Calculate the local horizon coordinates of each planet. First convert */
  807.   /* zodiac position and declination to zenith longitude and latitude.     */
  808.  
  809.   lat = RFromD(Lat);
  810.   for (i = 1; i <= cObj; i++) if (!ignore[i] || i == oMC) 
  811.   {
  812.     lonz[i] = RFromD(Tropical(planet[i])); latz[i] = RFromD(planetalt[i]);
  813.     EclToEqu(&lonz[i], &latz[i]);
  814.   }
  815.  
  816.   for (i = 1; i <= cObj; i++) if (FProper(i)) 
  817.   {
  818.     lonz[i] = RFromD(Mod(DFromR(lonz[oMC]-lonz[i]+rPiHalf)));
  819.     EquToLocal(&lonz[i], &latz[i], rPiHalf-lat);
  820.     azi[i] = rDegMax-DFromR(lonz[i]); alt[i] = rDegQuad-DFromR(latz[i]);
  821.     s = alt[i]/rDegQuad;
  822.     x[i] = cx+(int)(rx*s*RCosD(rDegHalf+azi[i])+rRound);
  823.     y[i] = cy+(int)(ry*s*RSinD(rDegHalf+azi[i])+rRound);
  824.     if (!FOnWin(x[i], y[i]))
  825.       x[i] = -1000;
  826.     m[i] = x[i]; n[i] = y[i]+unit/2;
  827.   }
  828.  
  829.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  830.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  831.   /* drawn on top of each other if possible. Again, we assume that we'll */
  832.   /* put the glyph right under the point, unless there would be some     */
  833.   /* overlap and the above position is better off.                       */
  834.  
  835.   for (i = 1; i <= cObj; i++) if (FProper(i)) 
  836.   {
  837.     k = l = gs.xWin+gs.yWin;
  838.     for (j = 1; j < i; j++) if (FProper(j)) 
  839.     {
  840.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  841.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  842.     }
  843.     if (k < unit || l < unit)
  844.       if (k < l)
  845.         n[i] -= unit;
  846.   }
  847.  
  848.   for (i = cObj; i >= 1; i--) if (m[i] >= x1 && FProper(i))  /* Draw glyph. */
  849.     DrawObject(i, m[i], n[i]);
  850.  
  851.   for (i = cObj; i >= 1; i--) if (x[i] >= y1 && FProper(i)) 
  852.   {
  853.     DrawColor(kObjB[i]);
  854.     if (!gs.fAlt || i > oNorm)
  855.       DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  856.     else                          /* near glyph indicating   */
  857.       DrawSpot(x[i], y[i]);       /* exact local location.   */
  858.   }
  859. }
  860.  
  861.  
  862. /* Draw a chart depicting an aerial view of the solar system in space, with */
  863. /* all the planets drawn around the Sun, and the specified central planet   */
  864. /* in the middle, as done when the -S is combined with the -X switch.       */
  865.  
  866. void XChartOrbit()
  867. {
  868.   int x[objMax], y[objMax], m[objMax], n[objMax],
  869.     cx = gs.xWin / 2, cy = gs.yWin / 2, unit, x1, y1, x2, y2, i, j, k, l;
  870.   real sx, sy, sz = 30.0, xp, yp, a;
  871.  
  872.   unit = Max(gs.fText*12, 6*gi.nScale);
  873.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  874.   unit = 12*gi.nScale;
  875.  
  876.   /* Determine the scale of the chart. For a scale size of 400+, make the */
  877.   /* graphic 1 AU in radius (just out to Earth's orbit). For 300, make    */
  878.   /* the chart 6 AU in radius (enough for inner planets out to asteroid   */
  879.   /* belt). For a scale of 200, make window 30 AU in radius (enough for   */
  880.   /* planets out to Neptune). For scale of 100, make it 90 AU in radius   */
  881.   /* (enough for all planets including the orbits of the uranians.)       */
  882.  
  883.   if (gi.nScale/gi.nScaleT < 2)
  884.     sz = 90.0;
  885.   else if (gi.nScale/gi.nScaleT == 3)
  886.     sz = 6.0;
  887.   else if (gi.nScale/gi.nScaleT > 3)
  888.     sz = 1.0;
  889.   sx = (real)(cx-x1)/sz; sy = (real)(cy-y1)/sz;
  890.  
  891.   for (i = 0; i <= oNorm; i++) if (FProper(i)) 
  892.   {
  893.     /* Determine what glyph corresponds to our current planet. Normally the */
  894.     /* array indices are the same, however we have to do some swapping for  */
  895.     /* non-geocentric based charts where a planet gets replaced with Earth. */
  896.  
  897.     if (us.objCenter == 0)
  898.       j = i < oMoo ? 1-i : i;
  899.     else if (us.objCenter == 1)
  900.       j = i;
  901.     else
  902.       j = i == 0 ? us.objCenter : (i == us.objCenter ? 0 : i);
  903.     xp = spacex[j]; yp = spacey[j];
  904.     x[i] = cx-(int)(xp*sx); y[i] = cy+(int)(yp*sy);
  905.     m[i] = x[i]; n[i] = y[i]+unit/2;
  906.   }
  907.  
  908.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  909.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  910.   /* drawn on top of each other if possible. Again, we assume that we'll */
  911.   /* put the glyph right under the point, unless there would be some     */
  912.   /* overlap and the above position is better off.                       */
  913.  
  914.   for (i = 0; i <= oNorm; i++) if (FProper(i)) 
  915.   {
  916.     k = l = gs.xWin+gs.yWin;
  917.  
  918.     for (j = 0; j < i; j++) if (FProper(j))
  919.     {
  920.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  921.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  922.     }
  923.     if (k < unit || l < unit)
  924.       if (k < l)
  925.         n[i] -= unit;
  926.   }
  927.  
  928.   /* Draw the 12 sign boundaries from the center body to edges of screen. */
  929.  
  930.   a = Mod(DFromR(Angle(spacex[oJup], spacey[oJup]))-planet[oJup]);
  931.   DrawColor(gi.kiGray);
  932.   for (i = 0; i < cSign; i++) {
  933.     k = cx+2*(int)((real)cx*RCosD((real)i*30.0+a));
  934.     l = cy+2*(int)((real)cy*RSinD((real)i*30.0+a));
  935.     DrawClip(cx, cy, k, l, x1, y1, x2, y2, 1);
  936.   }
  937.  
  938.   DrawColor(gi.kiLite);
  939.   DrawEdge(x1, y1, x2, y2);
  940.  
  941.   for (i = oNorm; i >= 0; i--)
  942.   {
  943.     if (FProper(i) && FInRect(m[i], n[i], x1, y1, x2, y2))
  944.       DrawObject(i, m[i], n[i]);
  945.   }
  946.  
  947.   for (i = oNorm; i >= 0; i--)
  948.   {
  949.     if (FProper(i) && FInRect(x[i], y[i], x1, y1, x2, y2))
  950.     {
  951.       DrawColor(kObjB[i]);
  952.       if (!gs.fAlt || i > oNorm)
  953.         DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  954.       else                          /* near glyph indicating   */
  955.         DrawSpot(x[i], y[i]);       /* exact orbital location. */
  956.     }
  957.   }
  958. }
  959.  
  960.  
  961. /* Draw an arrow from one point to another, a line with an arrowhead at the */
  962. /* ending point. The size of the arrowhead is based on current scale size,  */
  963. /* and the line segment is actually shorter and doesn't touch either        */
  964. /* endpoint by the same amount. This is used by XChartDispositor() below.   */
  965.  
  966. void DrawArrow(x1, y1, x2, y2)
  967. int x1, y1, x2, y2;
  968. {
  969.   real r, s, a;
  970.  
  971.   r = DFromR(Angle((real)(x2-x1), (real)(y2-y1)));
  972.   s = (real)(gi.nScale*gi.nScaleT*8);
  973.   x1 += (int)(s*RCosD(r)); y1 += (int)(s*RSinD(r));    /* Shrink line by    */
  974.   x2 -= (int)(s*RCosD(r)); y2 -= (int)(s*RSinD(r));    /* the scale amount. */
  975.   s = (real)(gi.nScale*gi.nScaleT)*4.5;
  976.   DrawLine(x1, y1, x2, y2);                            /* Main segment. */
  977.  
  978.   for (a = -1.0; a <= 1.0; a += 2.0)
  979.   {
  980.     DrawLine(x2, y2, x2 + (int)(s*RCosD(r + a*135.0)), /* The two arrow     */
  981.       y2 + (int)(s*RSinD(r + a*135.0)));               /* head line pieces. */
  982.   }
  983. }
  984.  
  985.  
  986. /* Draw dispositor graphs for the 10 main planets, as done when the -j is   */
  987. /* combined with the -X switch. Four graphs are drawn, one in each screen   */
  988. /* quadrant. A dispositor graph may be based on the sign or house position, */
  989. /* and the planets may be arranged in a hierarchy or a wheel format.        */
  990.  
  991. void XChartDispositor()
  992. {
  993.   int oDis[oMain+1], dLev[oMain+1], cLev[oMain+1], xo[oMain+1], yo[oMain+1];
  994.   real xCirc[oMain+1], yCirc[oMain+1];
  995.   char sz[cchSzDef];
  996.   int xLev, yLev, xSub, ySub, cx0, cy0, cx, cy, i, j, k;
  997.  
  998.   /* Set up screen positions of the 10 planets for the wheel graphs. */
  999.  
  1000.   cx0 = gs.xWin / 2; cy0 = gs.yWin / 2;
  1001.   for (i = 1; i <= oMain; i++) 
  1002.   {
  1003.     if ((j = (180-(i-1)*360/oMain)) < 0)
  1004.       j += nDegMax;
  1005.  
  1006.     xCirc[i] = (real)cx0*0.4*RCosD((real)j);
  1007.     yCirc[i] = (real)cy0*0.4*RSinD((real)j);
  1008.   }
  1009.  
  1010.   /* Loop over the two basic dispositor types: sign based and house based. */
  1011.  
  1012.   for (xSub = 0; xSub <= 1; xSub++) 
  1013.   {
  1014.     cx = xSub * cx0 + cx0 / 2;
  1015.  
  1016.     /* For each planet, get its dispositor planet for current graph type. */
  1017.  
  1018.     for (i = 1; i <= oMain; i++) {
  1019.       oDis[i] = rules[xSub ? inhouse[i] : SFromZ(planet[i])];
  1020.       dLev[i] = 1;
  1021.     }
  1022.  
  1023.     /* Determine the final dispositors (including mutual reception loops). */
  1024.  
  1025.     do
  1026.     {
  1027.       j = fFalse;
  1028.  
  1029.       for (i = 1; i <= oMain; i++)
  1030.         cLev[i] = fFalse;
  1031.  
  1032.       for (i = 1; i <= oMain; i++)
  1033.       {
  1034.         if (dLev[i])
  1035.           cLev[oDis[i]] = fTrue;
  1036.       }
  1037.  
  1038.       for (i = 1; i <= oMain; i++)    /* A planet isn't a final dispositor */
  1039.       {
  1040.         if (dLev[i] && !cLev[i])      /* if nobody is pointing to it.      */
  1041.         {
  1042.           dLev[i] = 0;
  1043.           j = fTrue;
  1044.         }
  1045.       }
  1046.     } while (j);
  1047.  
  1048.     /* Determine the level of each planet, i.e. how many times you have to */
  1049.     /* jump to your dispositor before reaching a final, with finals == 1.  */
  1050.  
  1051.     do {
  1052.       j = fFalse;
  1053.       for (i = 1; i <= oMain; i++)
  1054.         if (!dLev[i]) {
  1055.           if (!dLev[oDis[i]])
  1056.             j = fTrue;
  1057.           else                              /* If my dispositor already has */
  1058.             dLev[i] = dLev[oDis[i]] + 1;    /* a level, mine is one more.   */
  1059.         }
  1060.     } while (j);
  1061.  
  1062.     /* Count the number of planets at each dispositor level. */
  1063.  
  1064.     for (i = 1; i <= oMain; i++)
  1065.       cLev[i] = 0;
  1066.     for (i = 1; i <= oMain; i++)
  1067.       cLev[dLev[i]]++;
  1068.  
  1069.     /* Count the number of levels total, and max planets on any one level. */
  1070.  
  1071.     xLev = yLev = 0;
  1072.     for (i = 1; i <= oMain; i++)
  1073.       if (cLev[i]) {
  1074.         yLev = i;
  1075.         if (cLev[i] > xLev)
  1076.           xLev = cLev[i];
  1077.       }
  1078.  
  1079.     /* Loop over our two dispositor display formats: hierarchy and wheel. */
  1080.  
  1081.     for (ySub = 0; ySub <= 1; ySub++) 
  1082.     {
  1083.       cy = ySub * cy0 + cy0 / 2;
  1084.       sprintf(sz, "%s dispositor %s.", xSub ? "House" : "Sign",
  1085.                                        ySub ? "wheel" : "hierarchy");
  1086.       DrawColor(gi.kiLite);
  1087.       DrawSz(sz, cx, ySub * cy0 + 3*gi.nScaleT, dtTop);
  1088.  
  1089.       if (ySub) {
  1090.  
  1091.         /* Draw a graph in wheel format. */
  1092.  
  1093.         for (i = 1; i <= oMain; i++) 
  1094.         {
  1095.           DrawObject(i, cx + (int)xCirc[i], cy + (int)yCirc[i]);
  1096.           j = oDis[i];
  1097.  
  1098.           if (j != i)
  1099.           {
  1100.             if (dLev[i] < 2)
  1101.               DrawColor(gi.kiOn);
  1102.             else
  1103.               DrawColor(kObjB[i]);
  1104.  
  1105.             DrawArrow(cx + (int)xCirc[i], cy + (int)yCirc[i],
  1106.                       cx + (int)xCirc[j], cy + (int)yCirc[j]);
  1107.           }
  1108.  
  1109.           if (!gs.fAlt && (j == i || dLev[i] < 2))
  1110.           {
  1111.             DrawColor(j == i ? gi.kiOn : gi.kiGray);
  1112.             DrawCircle(cx + (int)xCirc[i], cy + (int)yCirc[i], 
  1113.               7*gi.nScale*gi.nScaleT, 7*gi.nScale*gi.nScaleT);
  1114.           }
  1115.         }
  1116.       } else {
  1117.  
  1118.         /* For level hierarchies, first figure out the screen coordinates    */
  1119.         /* for each planet, based on its level, total levels, and max width. */
  1120.  
  1121.         for (i = 1; i <= oMain; i++)
  1122.         {
  1123.           yo[i] = cy0*(dLev[i]*2-1)/(yLev*2);
  1124.           k = 0;
  1125.  
  1126.           for (j = 1; j < i; j++)
  1127.             if (dLev[i] == dLev[j])
  1128.               k = j;
  1129.  
  1130.           if (k)
  1131.             xo[i] = xo[k] + cx0/xLev;    /* One right of last one on level. */
  1132.           else
  1133.             xo[i] = cx - ((cx0/xLev)*(cLev[dLev[i]]-1)/2);
  1134.         }
  1135.  
  1136.         /* Draw graph in level hierarchy format. */
  1137.  
  1138.         for (i = 1; i <= oMain; i++) 
  1139.         {
  1140.           DrawObject(i, xo[i], yo[i]);
  1141.           j = oDis[i];
  1142.           if (j != i)
  1143.           {
  1144.             if (dLev[i] < 2) 
  1145.             {
  1146.               if (abs(xo[i] - xo[j]) < cx0/xLev*3/2) 
  1147.               {
  1148.                 DrawColor(gi.kiOn);
  1149.                 DrawArrow(xo[i], yo[i], xo[j], yo[j]);
  1150.               }
  1151.               DrawColor(gi.kiGray);
  1152.             } 
  1153.  
  1154.             else 
  1155.             {
  1156.               DrawColor(kObjB[i]);
  1157.               DrawArrow(xo[i], yo[i], xo[j], yo[j]);
  1158.             }
  1159.           } 
  1160.           else
  1161.             DrawColor(gi.kiOn);
  1162.  
  1163.           if (!gs.fAlt && dLev[i] < 2)
  1164.             DrawCircle(xo[i], yo[i], 7*gi.nScale*gi.nScaleT, 7*gi.nScale*gi.nScaleT);
  1165.         }
  1166.       }
  1167.     }
  1168.   }
  1169.  
  1170.   /* Draw boundary lines between the four separate dispositor graphs. */
  1171.  
  1172.   if (gs.fBorder) {
  1173.     DrawColor(gi.kiLite);
  1174.     DrawBlock(cx0, 0, cx0, gs.yWin);
  1175.     DrawBlock(0, cy0, gs.xWin, cy0);
  1176.   }
  1177. }
  1178.  
  1179.  
  1180. /* Draw a graphical calendar on the screen for the chart month, with     */
  1181. /* numbers in boxes, as done when the -K is combined with the -X switch. */
  1182.  
  1183. void XChartCalendar()
  1184. {
  1185.   char sz[cchSzDef];
  1186.   int day, cday, dayHi, cweek, xunit, yunit, x1, y1, x, y, s;
  1187.  
  1188.   day   = DayOfWeek(Mon, 1, Yea);  /* Day of week of 1st of month.     */
  1189.   cday  = DaysInMonth(Mon, Yea);   /* Count of days in the month.      */
  1190.   dayHi = DayInMonth(Mon, Yea);    /* Number of last day in the month. */
  1191.   cweek = us.fCalendarYear ? 6 : (day + cday + 6) / 7;   /* Week rows. */
  1192.   xunit = gs.xWin/8;               /* Hor. pixel size of each day box. */
  1193.   yunit = gs.yWin/(cweek+2);       /* Ver. pixel size of each day box. */
  1194.   x1 = (gs.xWin - xunit*7) / 2;    /* Blank space to left of calendar. */
  1195.   y1 = yunit*3/2;                  /* Blank space to top of calendar.  */
  1196.  
  1197.   /* Print the month and year in big letters at top of chart. */
  1198.  
  1199.   DrawColor(gi.kiOn);
  1200.   sprintf(sz, "%s, %d", szMonth[Mon], Yea);
  1201.  
  1202.   s = gi.nScaleT;
  1203.   gi.nScaleT = Min((yunit*3/2-yFontT*gi.nScale) / yFont, gs.xWin/CchSz(sz) / xFont);
  1204.   gi.nScaleT = Max(gi.nScaleT-1, 1);
  1205.  
  1206.   DrawSz(sz, gs.xWin/2, (yunit*3/2-yFont*gi.nScale)/2, dtCent);
  1207.  
  1208.   /* Draw the grid of boxes for the days. */
  1209.  
  1210.   gi.nScaleT = gi.nScale;
  1211.  
  1212.   for (x = 0; x <= 7; x++) {
  1213.  
  1214.     /* Print days of week at top of each column (abbreviated if need be). */
  1215.  
  1216.     if (xunit / xFontT < 9)
  1217.       sprintf(sz, "%c%c%c", chDay3(x));
  1218.     else
  1219.       sprintf(sz, "%s", szDay[x]);
  1220.  
  1221.     if (x < 7) 
  1222.     {
  1223.       DrawColor(kRainbowB[3]);
  1224.       DrawSz(sz, x1 + x*xunit + xunit/2, y1 - s*3, dtBottom);
  1225.       DrawColor(kRainbowB[5]);
  1226.     }
  1227.     DrawLine(x1 + x*xunit, y1, x1 + x*xunit, y1 + cweek*yunit);
  1228.   }
  1229.  
  1230.   for (y = 0; y <= cweek; y++)
  1231.     DrawLine(x1, y1 + y*yunit, x1 + 7*xunit, y1 + y*yunit);
  1232.  
  1233.   /* Actually draw the day numbers in their appropriate boxes. */
  1234.  
  1235.   x = day; y = 0;
  1236.  
  1237.   for (day = 1; day <= dayHi; day = AddDay(Mon, day, Yea, 1)) 
  1238.   {
  1239.     sprintf(sz, gs.fText ? "%2d" : "%d", day);
  1240.     DrawColor(day == Day && gs.fLabel ? kRainbowB[4] : (x <= 0 || x >= 6 ? kRainbowB[1] : gi.kiLite));
  1241.  
  1242.     if (!gs.fAlt)
  1243.       DrawSz(sz, x1 + x*xunit + s*2, y1 + y*yunit + s*4, dtLeft | dtTop);
  1244.     else
  1245.       DrawSz(sz, x1 + x*xunit + xunit/2,
  1246.         y1 + y*yunit + yunit/2 + gi.nScale, dtCent);
  1247.  
  1248.     if (++x >= 7) 
  1249.     {
  1250.       x = 0;
  1251.       y++;
  1252.     }
  1253.   }
  1254.   gi.nScaleT = s;
  1255. }
  1256.  
  1257.  
  1258. /* Draw a chart showing a graphical ephemeris for the given month (or year */
  1259. /* if -Ey in effect), with the date on the vertical access and the zodiac  */
  1260. /* on the horizontal, as done when the -E is combined with the -X switch.  */
  1261.  
  1262. void XChartEphemeris()
  1263. {
  1264.   real symbol[cObj*2+1], objSav[objMax];
  1265.   char sz[4];
  1266.   int yea, unit = 6*gi.nScale, daytot, d = 1, day, mon, monsiz,
  1267.     x1, y1, x2, y2, xs, ys, m, n, u, v, i, j;
  1268.  
  1269.   yea = us.nEphemYears;    /* Is this -Ey -X or just -E -X? */
  1270.  
  1271.   if (yea) 
  1272.   {
  1273.     daytot = DayInYearHi(Yea);
  1274.     day = 1; mon = 1; monsiz = 31;
  1275.   } 
  1276.   else daytot = DayInMonth(Mon, Yea);
  1277.  
  1278.   x1 = yea ? 30 : 24; y1 = unit*2; x2 = gs.xWin - x1; y2 = gs.yWin - y1;
  1279.   xs = x2 - x1; ys = y2 - y1;
  1280.  
  1281.   /* Display glyphs of the zodiac along the bottom axis. */
  1282.  
  1283.   for (i = 1; i <= cSign+1; i++) 
  1284.   {
  1285.     m = x1 + xs * (i-1) / 12;
  1286.     j = i > cSign ? 1 : i;
  1287.     DrawColor(kSignB(j));
  1288.     DrawSign(j, m, y2 + unit);
  1289.     DrawColor(gi.kiGray);
  1290.     DrawDash(m, y1, m, y2, 2);
  1291.   }
  1292.  
  1293.   /* Loop and display planet movements for one day segment. */
  1294.  
  1295.   while (d <= daytot + 1) 
  1296.   {
  1297.     n = v;
  1298.     v = y1 + NMultDiv(ys, d-1, daytot);
  1299.  
  1300.     if (!yea || day == 1) 
  1301.     {
  1302.       DrawColor(gi.kiGray);
  1303.       DrawDash(x1, v, x2, v, 1);    /* Marker line for day or month. */
  1304.     }
  1305.  
  1306.     if (d > 1)
  1307.     {
  1308.       for (i = 1; i <= cObj; i++)
  1309.         objSav[i] = planet[i];
  1310.     }
  1311.  
  1312.     if (yea) { MM = mon; DD = day; }
  1313.     else     { MM = Mon; DD = d;   }
  1314.  
  1315.     YY = Yea; TT = 0.0; SS = us.dstDef; ZZ = us.zonDef;
  1316.     OO = us.lonDef; AA = us.latDef;
  1317.     CastChart(fTrue);
  1318.  
  1319.     /* Draw planet glyphs along top of chart. */
  1320.  
  1321.     if (d < 2)
  1322.     {
  1323.       for (i = 1; i <= cObj; i++) 
  1324.       {
  1325.         symbol[i*2-1] = -rLarge;
  1326.  
  1327.         if (!FProper(i) || (i == oMoo && gs.fAlt))
  1328.           symbol[i*2] = -rLarge;
  1329.  
  1330.         else
  1331.           symbol[i*2] = planet[i];
  1332.       }
  1333.  
  1334.       FillSymbolLine(symbol);
  1335.  
  1336.       for (i = cObj; i >= 1; i--)
  1337.       {
  1338.         if (symbol[i*2] >= 0.0)
  1339.           DrawObject(i, x1 + (int)((real)xs * symbol[i*2] / rDegMax), unit);
  1340.       }
  1341.     }
  1342.  
  1343.     /* Draw a line segment for each object during this time section. */
  1344.  
  1345.     else
  1346.     {
  1347.       for (i = cObj; i >= 1; i--) 
  1348.       {
  1349.         if (!FProper(i) || (i == oMoo && gs.fAlt))
  1350.           continue;
  1351.  
  1352.         m = x1 + (int)((real)xs * objSav[i] / rDegMax);
  1353.         u = x1 + (int)((real)xs * planet[i] / rDegMax);
  1354.         DrawColor(kObjB[i]);
  1355.         DrawWrap(m, n, u, v, x1, x2);
  1356.       }
  1357.     }
  1358.  
  1359.     /* Label months or days in the month along the left and right edges. */
  1360.  
  1361.     if (d <= daytot && (!yea || day == 1))
  1362.     {
  1363.       if (yea) 
  1364.       {
  1365.         sprintf(sz, "%c%c%c", chMon3(mon));
  1366.         i = (mon == Mon);
  1367.       } 
  1368.       else 
  1369.       {
  1370.         sprintf(sz, "%2d", d);
  1371.         i = (d == Day);
  1372.       }
  1373.  
  1374.       DrawColor(i ? gi.kiOn : gi.kiLite);
  1375.       DrawSz(sz,     xFont   *gi.nScaleT, v + (yFont-2)*gi.nScaleT, dtLeft | dtBottom);
  1376.       DrawSz(sz, x2+(xFont-1)*gi.nScaleT, v + (yFont-2)*gi.nScaleT, dtLeft | dtBottom);
  1377.     }
  1378.  
  1379.     /* Now increment the day counter. For a month we always go up by one. */
  1380.     /* For a year we go up by four or until the end of the month reached. */
  1381.  
  1382.     if (yea) 
  1383.     {
  1384.       day += 4;
  1385.  
  1386.       if (day > monsiz)
  1387.       {
  1388.         d += 4-(day-monsiz-1);
  1389.  
  1390.         if (d <= daytot + 1)
  1391.         {
  1392.           mon++;
  1393.           monsiz = DayInMonth(mon, Yea);
  1394.           day = 1;
  1395.         }
  1396.       } 
  1397.       else d += 4;
  1398.     }
  1399.     else d++;
  1400.   }
  1401.  
  1402.   DrawColor(gi.kiLite);
  1403.   DrawEdge(x1, y1, x2, y2);
  1404.  
  1405.   ciCore = ciMain;    /* Recast original chart. */
  1406.   CastChart(fTrue);
  1407. }
  1408. #endif /* GRAPH */
  1409.  
  1410. /* xcharts1.c */
  1411.